import Web3 from 'web3';
import { logger } from '../models/LogModel';
import { Transaction } from 'web3-core/types';
import { toChecksumAddress } from 'web3-utils';
import { EthBlock, EthCoinType, EthUserAddress, EthConfig } from '../database/eth/EthDatabase';
import { contractAddressList, userEthAddressList, ethNodeUrl } from '../global';
import EthHandle from './coin/eth/EthHandle';
import EthTokenHandle from './coin/ethToken/EthTokenHandle';
import { isUndefined } from 'util';
const web3 = new Web3(ethNodeUrl);

// 载入监听地址
async function init() {
  // 载入合约地址
  let contractList = await EthCoinType.getEthContractAddressList();
  contractList.map(row => {
    try {
      contractAddressList.add(toChecksumAddress(row.contract_address));
    } catch (error) {
      logger('eth').debug(`合约校验错误 -- ${row.contract_address}`);
      throw `合约校验错误 -- ${row.contract_address}`;
    }
  });
  // 载入用户ETH地址
  let ethAddressList = await EthUserAddress.getUserEthAddressList();
  ethAddressList.map(row => {
    try {
      userEthAddressList.add(toChecksumAddress(row.address));
    } catch (error) {
      logger('eth').debug(`用户地址校验错误 -- ${row.contract_address}`);
      throw `用户地址校验错误 -- ${row.contract_address}`;
    }
  })
  await getBlockNum();
}


// 获取区块
async function getBlockNum() {
  // 获取数据库中的高度和确认数
  let blockObj = await EthBlock.getLastBlockNum();
  // 获取区块中的高度
  let blockHeigt = await web3.eth.getBlockNumber();
  let onBlockNum = blockObj? blockObj.block_num : blockObj;
  let onAffertNum = blockObj? blockObj.affert_num : blockObj;
  // 需要处理的高度
  let handleBlockHeight: number;
  
  if(onBlockNum) {
    if(onAffertNum < 1) {
      handleBlockHeight = onBlockNum;
    }else{
      if(blockHeigt - (onBlockNum + 1) < 4){
        await sellp(5000);
        return await getBlockNum();
      }else{
        handleBlockHeight = onBlockNum + 1;
      }
    }
  }else{
    handleBlockHeight = blockHeigt;
  }
  await handleBlock(handleBlockHeight);
}

// 处理区块
async function handleBlock(block: number) {
  logger('eth').info(`处理区块高度--${block}`);
  const BlockData = await web3.eth.getBlock(block, true);
  BlockData.transactions.map( transaction => {
    handleTransaction(transaction, block);
  })

  await EthBlock.saveBlockLog(BlockData.number, BlockData.transactions.length);
}

/**
 * 处理交易，分发交易
 * @param {Transaction} transaction
 * @param {number} block
 */
async function handleTransaction(transaction: Transaction, block: number) {
  // console.log(userEthAddressList.has(transaction.to));
  // 判断交易是否为合约
  if(contractAddressList.has(transaction.to)){
    // 分发此交易到合约
    const ethToken = new EthTokenHandle(transaction.hash);
    const tokenTransaction = await ethToken.buildTransactionMessage();
    // 当合约未成功执行时 ${tokenTransaction} 为空
    if(!isUndefined(tokenTransaction)){
      if(userEthAddressList.has(tokenTransaction.to)) {
        await ethToken.affertBlock();
        await ethToken.sendTransactionMessage();
        await ethToken.transfer();
      }
    }
  } else if(userEthAddressList.has(transaction.to)){ 
    // 分发到eth处理
    const gasAddress = await EthConfig.getParam('gas_address');
    if(transaction.from != toChecksumAddress(gasAddress)){
      const eth = new EthHandle(transaction, block);
      await eth.affertBlock();
      await eth.sendTransactionMessage();
      await eth.transfer();
    }
  }
}

function sellp(time: number) {
  return new Promise((resolve, reject) => {
    // logger('eth').trace(`暂停 ${time} 毫秒`);
    setTimeout(() =>{
      resolve();
    }, time);
  })
}

async function start() {
  await init();
  await start();
}

export default start;